package com.smart.campus.web.controller.school;

import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.ParseException;
import java.util.*;
import java.util.stream.Collectors;

import com.alibaba.fastjson.JSONArray;
import com.smart.campus.common.json.JSONObject;
import com.smart.campus.common.utils.DateUtils;
import com.smart.campus.school.domain.*;
import com.smart.campus.school.domain.vo.BaseClockInQuery;
import com.smart.campus.school.domain.vo.ClockInReportVo;
import com.smart.campus.school.service.IClassInfoService;
import com.smart.campus.school.service.IGradeService;
import com.smart.campus.school.service.IStudentService;
import com.smart.campus.web.utils.SchoolUtil;
import io.swagger.models.auth.In;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.smart.campus.common.annotation.Log;
import com.smart.campus.common.enums.BusinessType;
import com.smart.campus.school.service.IClockInRecordService;
import com.smart.campus.common.core.controller.BaseController;
import com.smart.campus.common.core.domain.AjaxResult;
import com.smart.campus.common.utils.poi.ExcelUtil;
import com.smart.campus.common.core.page.TableDataInfo;

/**
 * 考勤记录Controller
 * 
 * @author Zhihe.Li
 * @date 2020-05-29
 */
@Controller
@RequestMapping("/school/record")
public class ClockInRecordController extends BaseController
{
    public static final double I_100 = 100.0;
    private final String[] names = {"提前20分钟","提前10分钟","准时","迟到"};
    private String prefix = "school/record";

    @Autowired
    private IClockInRecordService clockInRecordService;

    @Autowired
    private IGradeService gradeService;
    @Autowired
    private IClassInfoService classInfoService;

    @Autowired
    private IStudentService studentService;

    @RequiresPermissions("school:record:view")
    @GetMapping("/{modeType}")
    public String record(@PathVariable("modeType") Integer modeType)
    {
        return prefix + (modeType == 1?"/recordTeacher":"/record");
    }

    @RequiresPermissions("school:record:report")
    @GetMapping("/report")
    public String report()
    {
        return prefix + "/report";
    }

    @RequiresPermissions("school:record:reportStudents")
    @GetMapping("/reportStudents/{id}")
    public String reportStudent(@PathVariable("id") Long userId,ModelMap mmp)
    {
        mmp.put("userId",userId);
        return prefix + "/reportStudent";
    }

    /**
     * 查询考勤记录列表
     */
    @RequiresPermissions("school:record:list")
    @PostMapping("/list")
    @ResponseBody
    public TableDataInfo list(ClockInRecord clockInRecord)
    {
        startPage();
        clockInRecord.setSchoolId(SchoolUtil.getSchoolId());
        List<ClockInRecord> list = clockInRecordService.selectClockInRecordList(clockInRecord);
        return getDataTable(list);
    }

    /**
     * 查询考勤统计,
     */
    @RequiresPermissions("school:record:reports")
    @GetMapping("/reports/{type}/{dtype}/{uid}")
    @ResponseBody
    public Map<String,Object> weekReport(@PathVariable("type") Integer type, @PathVariable("dtype") Integer dtype,@PathVariable("uid") Long uId)  {
//        type : 1：年级；2：班级;3:个人
//        dtype : 0:周；1：月；2：学期
        Map<String,Object> map = new HashMap<>();
        BaseClockInQuery query = new BaseClockInQuery();
        try{
            query.setSchoolId(SchoolUtil.getSchoolId());
            query.setUserType(2);
            Map<String, Object> params = new HashMap<>();
            Date bgDate = null,edDate = null;
            switch (dtype){
                case 1:
                    bgDate = DateUtils.getCurrentMonthStartTime();
                    edDate = DateUtils.getCurrentMonthEndTime();
                    break;
                case 2:
                    bgDate = DateUtils.getHalfYearStartTime();
                    edDate = DateUtils.getHalfYearEndTime();
                    break;
                default:
                    bgDate = DateUtils.getCurrentWeekDayStartTime();
                    edDate = DateUtils.getCurrentWeekDayEndTime();
                    break;
            }
            params.put("bgDate",bgDate);
            params.put("edDate",edDate);
            params.put("userId",uId);
            query.setParams(params);
            int days = DateUtils.getDaySum(bgDate,edDate);
            List<ClockInReportVo> datas = new ArrayList<>();
            if(type==1){
                map = getGradeReportDatas(map, query, datas,days);
            }
            if(type==2){
                map = getClazzReportDatas(map, query, datas,days);
            }
            if(type==3){
                map = getStudentsReportDatas(map, query, datas,days);
            }
        }catch (Exception e){
            e.printStackTrace();
        }

        return map;

    }

    /**
     *  获取年级考勤
     * @param map
     * @param query
     * @param datas
     * @return
     */
    private Map<String, Object> getGradeReportDatas(Map<String, Object> map, BaseClockInQuery query, List<ClockInReportVo> datas,int days) {
        Grade grade = new Grade();
        grade.setShcoolId(SchoolUtil.getSchoolId());
        List<Grade> gradeList = gradeService.selectGradeList(grade);
        if(CollectionUtils.isNotEmpty(gradeList)){
            String[] xAxis = new String[gradeList.size()];
            Map<Long,Integer> gradeMap= new HashMap<>();//存放这的是年级Id和所属下标
            for (int i=0;i<gradeList.size();i++) {
                Grade grade0 = gradeList.get(i);
                xAxis[i] = grade0.getGradeName();
                ClockInReportVo clockInReportVo = new ClockInReportVo();
                clockInReportVo.setId(grade0.getId());
                clockInReportVo.setName(grade0.getGradeName());
                Integer stCount = grade0.getStudentCount();
                if(stCount==null){
                    clockInReportVo.setTotal(0);
                }else{
                    clockInReportVo.setTotal(stCount*3*days);
                }
                clockInReportVo.setDutyNum(0);
                clockInReportVo.setAdvanceTwenty(0);
                clockInReportVo.setAdvanceTen(0);
                gradeMap.put(clockInReportVo.getId(),i);
                datas.add(clockInReportVo);
            }
            map.put("xAxis",xAxis);
            //查询提前20分钟
            query.getParams().put("min",20);
            query.getParams().put("status",0);
            List<ClockInReportVo> list = clockInRecordService.queryClockInDataGrade(query);
            if(CollectionUtils.isNotEmpty(list)){
                for (ClockInReportVo vo:list) {
                    if(vo.getCounts()!=null){
                        int idx = gradeMap.get(vo.getId());
                        ClockInReportVo tj = datas.get(idx);
                        tj.setAdvanceTwenty(vo.getCounts());
                        datas.set(idx,tj);
                    }
                }
            }

            query.getParams().put("min",10);
            query.getParams().put("max",19);
            list = clockInRecordService.queryClockInDataGrade(query);
            if(CollectionUtils.isNotEmpty(list)){
                for (ClockInReportVo vo:list) {
                    if(vo.getCounts()!=null){
                        int idx = gradeMap.get(vo.getId());
                        ClockInReportVo tj = datas.get(idx);
                        tj.setAdvanceTen(vo.getCounts());
                    }
                }
            }

            query.getParams().put("min",0);
            query.getParams().put("max",9);
            list = clockInRecordService.queryClockInDataGrade(query);
            if(CollectionUtils.isNotEmpty(list)){
                for (ClockInReportVo vo:list) {
                    if(vo.getCounts()!=null){
                        int idx = gradeMap.get(vo.getId());
                        ClockInReportVo tj = datas.get(idx);
                        tj.setOnTime(vo.getCounts());
                    }
                }
            }

            query.getParams().remove("min");
            query.getParams().remove("max");
            query.getParams().put("status",1);
            list = clockInRecordService.queryClockInDataGrade(query);
            if(CollectionUtils.isNotEmpty(list)){
                for (ClockInReportVo vo:list) {
                    if(vo.getCounts()!=null){
                        int idx = gradeMap.get(vo.getId());
                        ClockInReportVo tj = datas.get(idx);
                        tj.setDutyNum(vo.getCounts());
                    }
                }
            }
            JSONArray series = new JSONArray();

            map.put("legend",names);
            for(int k=0;k<names.length;k++){
                String name = names[k];
                JSONObject sero = new JSONObject();
                sero.set("name",name);
                sero.set("type","bar");
                JSONArray sdata = new JSONArray();
                switch (k){
                    case 0:
                        for (int m=0;m<datas.size();m++) {
                            ClockInReportVo vo = datas.get(m);
                            if(vo.getTotal()==null||vo.getTotal()==0){
                                sdata.add(0);
                            }else{
                                int total = vo.getTotal();
                                int tw = vo.getAdvanceTwenty()==null?0:vo.getAdvanceTwenty();
                                sdata.add(makePoints3(tw*I_100/total));
                            }
                        }
                        break;
                    case 1:
                        for (int m=0;m<datas.size();m++) {
                            ClockInReportVo vo = datas.get(m);
                            if(vo.getTotal()==null||vo.getTotal()==0){
                                sdata.add(0);
                            }else{
                                int total = vo.getTotal();
                                int tn = vo.getAdvanceTen()==null?0:vo.getAdvanceTen();
                                sdata.add(makePoints3(tn* I_100 /total));
                            }
                        }
                        break;
                    case 2:
                        for (int m=0;m<datas.size();m++) {
                            ClockInReportVo vo = datas.get(m);
                            if(vo.getTotal()==null||vo.getTotal()==0){
                                sdata.add(0);
                            }else{
                                int total = vo.getTotal();
                                int on = vo.getOnTime()==null?0:vo.getOnTime();
                                sdata.add(makePoints3(on*I_100/total));
                            }
                        }
                        break;
                    case 3:
                        for (int m=0;m<datas.size();m++) {
                            ClockInReportVo vo = datas.get(m);
                            if(vo.getTotal()==null||vo.getTotal()==0){
                                sdata.add(0);
                            }else{
                                int total = vo.getTotal();
                                int dy = vo.getDutyNum()==null?0:vo.getDutyNum();
                                sdata.add(makePoints3(dy*I_100/total));
                            }
                        }
                        break;
                }
                sero.set("data",sdata);
                series.add(sero);
            }
            map.put("series",series);
            map.put("datas",datas);
        }
        return map;
    }

    /**
     *  获取班级考勤
     * @param map
     * @param query
     * @param datas
     * @return
     */
    private Map<String, Object> getClazzReportDatas(Map<String, Object> map, BaseClockInQuery query, List<ClockInReportVo> datas,int days) {
        ClassInfo clazz = new ClassInfo();
        clazz.setDeptId(SchoolUtil.getSchoolId());
        List<ClassInfo> gradeList = classInfoService.selectClassInfoList(clazz);
        if(CollectionUtils.isNotEmpty(gradeList)){
            String[] xAxis = new String[gradeList.size()];
            Map<Long,Integer> clazzMap= new HashMap<>();//存放这的是年级Id和所属下标
            for (int i=0;i<gradeList.size();i++) {
                ClassInfo calzz0 = gradeList.get(i);
                xAxis[i] = calzz0.getClassName();
                ClockInReportVo clockInReportVo = new ClockInReportVo();
                clockInReportVo.setId(calzz0.getId());
                clockInReportVo.setName(calzz0.getClassName());
                Integer stCount = calzz0.getStudentCount();
                if(stCount==null){
                    clockInReportVo.setTotal(0);
                }else{
                    clockInReportVo.setTotal(stCount*3*days);
                }
                clockInReportVo.setDutyNum(0);
                clockInReportVo.setAdvanceTwenty(0);
                clockInReportVo.setAdvanceTen(0);
                clazzMap.put(clockInReportVo.getId(),i);
                datas.add(clockInReportVo);
            }
            map.put("xAxis",xAxis);
            //查询提前20分钟
            query.getParams().put("min",20);
            query.getParams().put("status",0);
            List<ClockInReportVo> list = clockInRecordService.queryClockInDataClazz(query);
            if(CollectionUtils.isNotEmpty(list)){
                for (ClockInReportVo vo:list) {
                    if(vo.getCounts()!=null){
                        int idx = clazzMap.get(vo.getId());
                        ClockInReportVo tj = datas.get(idx);
                        tj.setAdvanceTwenty(vo.getCounts());
                        datas.set(idx,tj);
                    }
                }
            }

            query.getParams().put("min",10);
            query.getParams().put("max",19);
            list = clockInRecordService.queryClockInDataClazz(query);
            if(CollectionUtils.isNotEmpty(list)){
                for (ClockInReportVo vo:list) {
                    if(vo.getCounts()!=null){
                        int idx = clazzMap.get(vo.getId());
                        ClockInReportVo tj = datas.get(idx);
                        tj.setAdvanceTen(vo.getCounts());
                    }
                }
            }

            query.getParams().put("min",0);
            query.getParams().put("max",9);
            list = clockInRecordService.queryClockInDataClazz(query);
            if(CollectionUtils.isNotEmpty(list)){
                for (ClockInReportVo vo:list) {
                    if(vo.getCounts()!=null){
                        int idx = clazzMap.get(vo.getId());
                        ClockInReportVo tj = datas.get(idx);
                        tj.setOnTime(vo.getCounts());
                    }
                }
            }

            query.getParams().remove("min");
            query.getParams().remove("max");
            query.getParams().put("status",1);
            list = clockInRecordService.queryClockInDataClazz(query);
            if(CollectionUtils.isNotEmpty(list)){
                for (ClockInReportVo vo:list) {
                    if(vo.getCounts()!=null){
                        int idx = clazzMap.get(vo.getId());
                        ClockInReportVo tj = datas.get(idx);
                        tj.setDutyNum(vo.getCounts());
                    }
                }
            }
            JSONArray series = new JSONArray();
            map.put("legend",names);
            for(int k=0;k<names.length;k++){
                String name = names[k];
                JSONObject sero = new JSONObject();
                sero.set("name",name);
                sero.set("type","line");
                JSONArray sdata = new JSONArray();
                switch (k){
                    case 0:
                        for (int m=0;m<datas.size();m++) {
                            ClockInReportVo vo = datas.get(m);
                            if(vo.getTotal()==null||vo.getTotal()==0){
                                sdata.add(0);
                            }else{
                                int total = vo.getTotal();
                                int tw = vo.getAdvanceTwenty()==null?0:vo.getAdvanceTwenty();
                                sdata.add(makePoints3(tw*I_100/total));
                            }
                        }
                        break;
                    case 1:
                        for (int m=0;m<datas.size();m++) {
                            ClockInReportVo vo = datas.get(m);
                            if(vo.getTotal()==null||vo.getTotal()==0){
                                sdata.add(0);
                            }else{
                                int total = vo.getTotal();
                                int tn = vo.getAdvanceTen()==null?0:vo.getAdvanceTen();
                                sdata.add(makePoints3(tn*I_100/total));
                            }
                        }
                        break;
                    case 2:
                        for (int m=0;m<datas.size();m++) {
                            ClockInReportVo vo = datas.get(m);
                            if(vo.getTotal()==null||vo.getTotal()==0){
                                sdata.add(0);
                            }else{
                                int total = vo.getTotal();
                                int on = vo.getOnTime()==null?0:vo.getOnTime();
                                sdata.add(makePoints3(on*I_100/total));
                            }
                        }
                        break;
                    case 3:
                        for (int m=0;m<datas.size();m++) {
                            ClockInReportVo vo = datas.get(m);
                            if(vo.getTotal()==null||vo.getTotal()==0){
                                sdata.add(0);
                            }else{
                                int total = vo.getTotal();
                                int dy = vo.getDutyNum()==null?vo.getDutyNum():0;
                                sdata.add(makePoints3(dy*I_100/total));
                            }
                        }
                        break;
                }
                sero.set("data",sdata);
                series.add(sero);
            }
            map.put("series",series);
            map.put("datas",datas);
        }
        return map;
    }

    /**
     *  获取班级考勤
     * @param map
     * @param query
     * @param datas
     * @param days 间隔天数
     * @return
     */
    private Map<String, Object> getStudentsReportDatas(Map<String, Object> map, BaseClockInQuery query, List<ClockInReportVo> datas,int days) {
        Long id = (Long)query.getParams().get("userId");
        Student student = studentService.selectStudentById(id);
        if(student!=null){
            String[] xAxis = new String[1];
            Map<Long,Integer> clazzMap= new HashMap<>();//存放这的是年级Id和所属下标
            ClockInReportVo clockInReportVo = new ClockInReportVo();
            clockInReportVo.setId(student.getId());
            clockInReportVo.setName(student.getStudentName());
            clockInReportVo.setTotal(3*days);
            clockInReportVo.setDutyNum(0);
            clockInReportVo.setAdvanceTwenty(0);
            clockInReportVo.setAdvanceTen(0);
            clazzMap.put(student.getId(),0);
            datas.add(clockInReportVo);
            xAxis[0] = student.getStudentName();
            map.put("xAxis",xAxis);
            //查询提前20分钟
            query.getParams().put("min",20);
            query.getParams().put("status",0);
            List<ClockInReportVo> list = clockInRecordService.queryClockInDataStudent(query);
            if(CollectionUtils.isNotEmpty(list)){
                for (ClockInReportVo vo:list) {
                    if(vo.getCounts()!=null){
                        int idx = clazzMap.get(vo.getId());
                        ClockInReportVo tj = datas.get(idx);
                        tj.setAdvanceTwenty(vo.getCounts());
                        datas.set(idx,tj);
                    }
                }
            }

            query.getParams().put("min",10);
            query.getParams().put("max",19);
            list = clockInRecordService.queryClockInDataStudent(query);
            if(CollectionUtils.isNotEmpty(list)){
                for (ClockInReportVo vo:list) {
                    if(vo.getCounts()!=null){
                        int idx = clazzMap.get(vo.getId());
                        ClockInReportVo tj = datas.get(idx);
                        tj.setAdvanceTen(vo.getCounts());
                    }
                }
            }

            query.getParams().put("min",0);
            query.getParams().put("max",9);
            list = clockInRecordService.queryClockInDataStudent(query);
            if(CollectionUtils.isNotEmpty(list)){
                for (ClockInReportVo vo:list) {
                    if(vo.getCounts()!=null){
                        int idx = clazzMap.get(vo.getId());
                        ClockInReportVo tj = datas.get(idx);
                        tj.setOnTime(vo.getCounts());
                    }
                }
            }

            query.getParams().remove("min");
            query.getParams().remove("max");
            query.getParams().put("status",1);
            list = clockInRecordService.queryClockInDataStudent(query);
            if(CollectionUtils.isNotEmpty(list)){
                for (ClockInReportVo vo:list) {
                    if(vo.getCounts()!=null){
                        int idx = clazzMap.get(vo.getId());
                        ClockInReportVo tj = datas.get(idx);
                        tj.setDutyNum(vo.getCounts());
                    }
                }
            }
            JSONArray series = new JSONArray();
            map.put("legend",names);
            for(int k=0;k<names.length;k++){
                String name = names[k];
                JSONObject sero = new JSONObject();
                sero.set("name",name);
                sero.set("type","bar");
                JSONArray sdata = new JSONArray();
                switch (k){
                    case 0:
                        for (int m=0;m<datas.size();m++) {
                            ClockInReportVo vo = datas.get(m);
                            if(vo.getTotal()==null||vo.getTotal()==0){
                                sdata.add(0);
                            }else{
                                int total = vo.getTotal();
                                int tw = vo.getAdvanceTwenty()==null?0:vo.getAdvanceTwenty();
                                sdata.add(makePoints3(tw*I_100/total));
                            }
                        }
                        break;
                    case 1:
                        for (int m=0;m<datas.size();m++) {
                            ClockInReportVo vo = datas.get(m);
                            if(vo.getTotal()==null||vo.getTotal()==0){
                                sdata.add(0);
                            }else{
                                int total = vo.getTotal();
                                int tn = vo.getAdvanceTen()==null?0:vo.getAdvanceTen();
                                sdata.add(makePoints3(tn*I_100/total));
                            }
                        }
                        break;
                    case 2:
                        for (int m=0;m<datas.size();m++) {
                            ClockInReportVo vo = datas.get(m);
                            if(vo.getTotal()==null||vo.getTotal()==0){
                                sdata.add(0);
                            }else{
                                int total = vo.getTotal();
                                int on = vo.getOnTime()==null?0:vo.getOnTime();
                                sdata.add(makePoints3(on*I_100/total));
                            }
                        }
                        break;
                    case 3:
                        for (int m=0;m<datas.size();m++) {
                            ClockInReportVo vo = datas.get(m);
                            if(vo.getTotal()==null||vo.getTotal()==0){
                                sdata.add(0);
                            }else{
                                int total = vo.getTotal();
                                int dy = vo.getDutyNum()==null?0:vo.getDutyNum();
                                sdata.add(makePoints3(dy*I_100/total));
                            }
                        }
                        break;
                }
                sero.set("data",sdata);
                series.add(sero);
            }
            map.put("series",series);
            map.put("datas",datas);
        }
        return map;
    }

    /**
     * 导出考勤记录列表
     */
    @RequiresPermissions("school:record:export")
    @Log(title = "考勤记录", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    @ResponseBody
    public AjaxResult export(ClockInRecord clockInRecord)
    {
        List<ClockInRecord> list = clockInRecordService.selectClockInRecordList(clockInRecord);
        ExcelUtil<ClockInRecord> util = new ExcelUtil<ClockInRecord>(ClockInRecord.class);
        return util.exportExcel(list, "record");
    }

    /**
     * 新增考勤记录
     */
    @GetMapping("/add/{modeType}")
    public String add(@PathVariable("modeType") Integer modeType)
    {
        return prefix + (modeType == 1?"/addTeacher":"/add");
    }

    /**
     * 新增保存考勤记录
     */
    @RequiresPermissions("school:record:add")
    @Log(title = "考勤记录", businessType = BusinessType.INSERT)
    @PostMapping("/add")
    @ResponseBody
    public AjaxResult addSave(ClockInRecord clockInRecord)
    {
        clockInRecord.setSchoolId(SchoolUtil.getSchoolId());
        return toAjax(clockInRecordService.insertClockInRecord(clockInRecord));
    }

    /**
     * 修改考勤记录
     */
    @GetMapping("/edit/{id}")
    public String edit(@PathVariable("id") Long id, ModelMap mmap)
    {
        ClockInRecord clockInRecord = clockInRecordService.selectClockInRecordById(id);
        mmap.put("clockInRecord", clockInRecord);
        int modeType = clockInRecord.getUserType();
        return prefix + (modeType == 1 ? "/editTeacher" : "/edit");
    }

    /**
     * 修改保存考勤记录
     */
    @RequiresPermissions("school:record:edit")
    @Log(title = "考勤记录", businessType = BusinessType.UPDATE)
    @PostMapping("/edit")
    @ResponseBody
    public AjaxResult editSave(ClockInRecord clockInRecord)
    {
        return toAjax(clockInRecordService.updateClockInRecord(clockInRecord));
    }

    public static double makePoints3(double numbers) {
        return makePoints(numbers,3);
    }
    public static double makePoints(double numbers, int size) {
        BigDecimal b = new BigDecimal(numbers);
        // 保留2位小数
        double f1 = b.setScale(size, BigDecimal.ROUND_HALF_UP).doubleValue();
        return f1;
    }

    /**
     * 删除考勤记录
     */
    @RequiresPermissions("school:record:remove")
    @Log(title = "考勤记录", businessType = BusinessType.DELETE)
    @PostMapping( "/remove")
    @ResponseBody
    public AjaxResult remove(String ids)
    {
        return toAjax(clockInRecordService.deleteClockInRecordByIds(ids));
    }
}
